package cn.csc.framework.pay.core.client.impl.lkl;

import cn.csc.framework.common.util.json.JsonUtils;
import cn.csc.framework.pay.core.client.PayCommonResult;
import cn.csc.framework.pay.core.client.dto.PayOrderUnifiedReqDTO;
import cn.csc.framework.pay.core.client.dto.PayOrderUnifiedRespDTO;
import cn.csc.framework.pay.core.client.dto.PayRefundUnifiedReqDTO;
import cn.csc.framework.pay.core.client.dto.PayRefundUnifiedRespDTO;
import cn.csc.framework.pay.core.client.impl.lkl.dto.V3LabsTradeAlipayAccBusiFieldInfo;
import cn.csc.framework.pay.core.client.impl.lkl.dto.V3LabsTradeUnionPayAccBusiFieldInfo;
import cn.csc.framework.pay.core.client.impl.lkl.dto.V3LabsTradeWechatAccBusiFieldInfo;
import cn.csc.framework.pay.core.enums.channel.PayChannelEnum;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.StrUtil;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.lkl.laop.sdk.exception.SDKException;
import com.lkl.laop.sdk.request.V3LabsTransPreorderRequest;
import com.lkl.laop.sdk.request.V3LabsTransRelationRefundRequest;
import com.lkl.laop.sdk.request.model.V3LabsTradeLocationInfo;
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderAlipayBus;
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderUnionPayBus;
import com.lkl.laop.sdk.request.model.V3LabsTradePreorderWechatBus;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.Map;
import java.util.Optional;

import static cn.hutool.core.date.DatePattern.*;

/**
 * 聚合扫码主扫客户端
 * 消费者扫商户二维码完成下单支付，支持支付宝，微信，云闪付等支付方式
 * http://open.lakala.com/#/home/document/detail?title=%E6%8E%A5%E5%85%A5%E8%A7%84%E8%8C%83&id=110
 * @author liuchuang
 * @version 1.0
 * @date 2023/11/1 11:55
 * @modify
 */
@Slf4j
public class LKLScanQrPayClient extends AbstractLklpayClient<LKLPayClientConfig> {

    private static final Gson gson = new Gson();

    public LKLScanQrPayClient(BigInteger channelId, LKLPayClientConfig config) {
        super(channelId, PayChannelEnum.LKL_SCAN_QR.getCode(), config, new LKLPayCodeMapping());
    }

    /**
     * 聚合主扫
     */
    @Override
    protected PayCommonResult<?> doUnifiedOrder(PayOrderUnifiedReqDTO reqDTO) throws Throwable {
        // 聚合主扫请求参数
        V3LabsTransPreorderRequest request = new V3LabsTransPreorderRequest();
        request.setMerchantNo(config.getMerchantNo());
        request.setTermNo(config.getTermNo());
        request.setOutTradeNo(reqDTO.getMerchantOrderId());
        String accountType = reqDTO.getChannelExtras().get("accountType");
        request.setAccountType(accountType);
        // 41:NATIVE（（ALIPAY，云闪付支持）
        //51:JSAPI（微信公众号支付，支付宝服务窗支付，银联JS支付，翼支付JS支付、拉卡拉钱包支付）
        //71:微信小程序支付
        request.setTransType(reqDTO.getChannelExtras().get("transType"));
        request.setTotalAmount(formatAmount(reqDTO.getAmount()));

        //地址位置信息
        V3LabsTradeLocationInfo locationInfo = new V3LabsTradeLocationInfo(reqDTO.getUserIp());
        request.setLocationInfo(locationInfo);

        request.setSubject(reqDTO.getSubject());
        request.setPayOrderNo(reqDTO.getChannelExtras().get("payOrderNo"));
        request.setNotifyUrl(reqDTO.getReturnUrl());
        String settleType = StringUtils.hasLength(reqDTO.getChannelExtras().get("settleType")) ? reqDTO.getChannelExtras().get("settleType") : "0";
        request.setSettleType(settleType);
        request.setRemark(reqDTO.getRemark());
        request.setPromoInfo(reqDTO.getChannelExtras().get("promoInfo"));

        String accBusiFields = reqDTO.getChannelExtras().get("accBusiFields");
        // 微信支付
        if ("WECHAT".equals(accountType)){
            //微信主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradePreorderWechatBus.class)));
        } else if ("ALIPAY".equals(accountType)){
            //支付宝主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradePreorderAlipayBus.class)));
        } else if ("UQRCODEPAY".equals(accountType)){
            //银联主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradePreorderUnionPayBus.class)));
        }

        log.info("[doUnifiedOrder][request({})]", JsonUtils.toJsonString(request));
        //3. 发送请求
        String response;
        try {
            response = getClient().httpPost(request);
        } catch (SDKException e){
            log.error("[doUnifiedOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e);
            return PayCommonResult.build(e.getCode(), e.getMessage(), null, codeMapping);
        }

        JsonObject json = gson.toJsonTree(response).getAsJsonObject();

        return PayCommonResult.build(StrUtil.blankToDefault(json.get("code").getAsString(),"BBS00000")
                ,json.get("msg").getAsString(), json.get("resp_data").getAsString(), codeMapping);

    }

    @Override
    protected PayCommonResult<PayRefundUnifiedRespDTO> doUnifiedRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
        return null;
    }

    /**
     * 聚合主扫
     */
    @Override
    protected PayOrderUnifiedRespDTO doUnifiedBeanOrder(PayOrderUnifiedReqDTO reqDTO) throws Throwable {
        log.info("[doUnifiedBeanOrder][reqDTO({})]",reqDTO);
        // 聚合主扫请求参数
        V3LabsTransPreorderRequest request = new V3LabsTransPreorderRequest();
        request.setMerchantNo(config.getMerchantNo());
        request.setTermNo(config.getTermNo());
        request.setOutTradeNo(reqDTO.getMerchantOrderId());
        String accountType = reqDTO.getChannelExtras().get("accountType");
        request.setAccountType(accountType);
        // 41:NATIVE（（ALIPAY，云闪付支持）
        //51:JSAPI（微信公众号支付，支付宝服务窗支付，银联JS支付，翼支付JS支付、拉卡拉钱包支付）
        //71:微信小程序支付
        request.setTransType(reqDTO.getChannelExtras().get("transType"));
        request.setTotalAmount(String.valueOf(reqDTO.getAmount()));

        //地址位置信息
        V3LabsTradeLocationInfo locationInfo = new V3LabsTradeLocationInfo(reqDTO.getUserIp());
        request.setLocationInfo(locationInfo);

        request.setSubject(reqDTO.getSubject());
        request.setPayOrderNo(reqDTO.getChannelExtras().get("payOrderNo"));
        request.setNotifyUrl(reqDTO.getNotifyUrl());
        String settleType = StringUtils.hasLength(reqDTO.getChannelExtras().get("settleType")) ? reqDTO.getChannelExtras().get("settleType") : "0";
        request.setSettleType(settleType);
        request.setRemark(reqDTO.getRemark());
        request.setPromoInfo(reqDTO.getChannelExtras().get("promoInfo"));

        String accBusiFields = reqDTO.getChannelExtras().get("accBusiFields");
        log.info("[doUnifiedBeanOrder][accBusiFields({})]",accBusiFields);
        // 微信支付
        if ("WECHAT".equals(accountType)){
            //微信主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradeWechatAccBusiFieldInfo.class)));
        } else if ("ALIPAY".equals(accountType)){
            //支付宝主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradeAlipayAccBusiFieldInfo.class)));
        } else if ("UQRCODEPAY".equals(accountType)){
            //银联主扫场景下acc_busi_fields域内容
            Optional.ofNullable(accBusiFields).ifPresent(acc -> request.setAccBusiFields(gson.fromJson(acc, V3LabsTradeUnionPayAccBusiFieldInfo.class)));
        }

        log.info("[doUnifiedOrder][request({})]", JsonUtils.toJsonString(request));
        //3. 发送请求
        JsonObject response;
        try {
            response = client.httpPostJson(request);
        } catch (SDKException e){
            log.error("[doUnifiedBeanOrder][request({}) 发起支付失败]", JsonUtils.toJsonString(reqDTO), e);
            throw new RuntimeException(e.getCode(),e);
        }

        //4. 处理结果
        JsonObject respData = response.getAsJsonObject("resp_data");
        // 支付成功
        if ("BBS00000".equals(response.get("code").getAsString())){
            JsonObject accRespFields = respData.get("acc_resp_fields").getAsJsonObject();
            Map<String, String> dataMap = Maps.newHashMap();
            dataMap.put("timeStamp",accRespFields.get("time_stamp").getAsString());
            dataMap.put("nonceStr",accRespFields.get("nonce_str").getAsString());
            dataMap.put("package",accRespFields.get("package").getAsString());
            dataMap.put("signType",accRespFields.get("sign_type").getAsString());
            dataMap.put("paySign",accRespFields.get("pay_sign").getAsString());
            String tradeTime = LocalDateTimeUtil.formatNormal(LocalDateTimeUtil.parse(response.get("resp_time").getAsString(), PURE_DATETIME_FORMATTER));
            return PayOrderUnifiedRespDTO.successOf(respData.get("trade_no").getAsString(),"",
                    tradeTime,respData.get("trade_no").getAsString(),respData.get("out_trade_no").getAsString(),
                    respData.toString(), dataMap);
        }

        // merchantOrderNo为V3LabsTransPreorderRequest.outTradeNo
        return PayOrderUnifiedRespDTO.closedOf(response.get("code").getAsString(),response.get("msg").getAsString(),
                respData.get("out_trade_no").getAsString(), respData.toString());
    }

    @Override
    protected PayRefundUnifiedRespDTO doUnifiedBeanRefund(PayRefundUnifiedReqDTO reqDTO) throws Throwable {
        V3LabsTransRelationRefundRequest request = new V3LabsTransRelationRefundRequest();
        request.setMerchantNo(config.getMerchantNo());
        request.setTermNo(config.getTermNo());
        // 商户交易流水号, 商户系统唯一, 商户端生成
        request.setOutTradeNo(reqDTO.getMerchantRefundId());
        request.setRefundAmount(String.valueOf(reqDTO.getRefundAmount()));
        request.setRefundReason(reqDTO.getReason());
        // 下单时的商户请求流水号(out_trade_no)
        request.setOriginOutTradeNo(reqDTO.getPayTradeNo());
        // 下单成功时，返回的拉卡拉交易流水(trade_no)。 origin_out_trade_no、origin_log_no、origin_trade_no至少一个必填
        request.setOriginTradeNo(reqDTO.getChannelOrderNo());
        // 下单成功时，返回的拉卡拉交易流水(log_no),拉卡拉退款请求的origin_log_no
        request.setOriginLogNo(reqDTO.getMerchantOrderId());

        V3LabsTradeLocationInfo locationInfo = new V3LabsTradeLocationInfo(reqDTO.getUserIp());
        request.setLocationInfo(locationInfo);

        //3. 发送请求
        JsonObject response;
        try {
            response = getClient().httpPostJson(request);
        } catch (SDKException e){
            log.error("[doUnifiedBeanRefund][request({}) 发起退款失败]", JsonUtils.toJsonString(reqDTO), e);
            throw new RuntimeException(e.getCode(),e);
        }

        // 4. 处理结果
        JsonObject respData = response.getAsJsonObject("resp_data");
        // 退款成功
        if ("BBS00000".equals(response.get("code").getAsString())){
            LocalDateTime tradeTime = LocalDateTimeUtil.parse(respData.get("trade_time").getAsString(), PURE_DATETIME_PATTERN);
            return PayRefundUnifiedRespDTO.successOf(respData.get("trade_no").getAsString(), LocalDateTimeUtil.format(tradeTime, NORM_DATETIME_PATTERN),
                    respData.get("out_trade_no").getAsString(), respData.toString());
        }

        // 退款失败
        return PayRefundUnifiedRespDTO.failureOf(response.get("code").getAsString(),response.get("msg").getAsString(),
                respData.get("out_trade_no").getAsString(), respData.toString());
        }


    protected void validateSuccess(JsonObject response) throws SDKException {
        if ("BBS00000".equals(response.get("code").getAsString())) {
            return;
        }
        throw new SDKException(response.get("code").getAsString(), response.get("msg").getAsString());
    }

}
